package com.km.algorithm

/**
  * Created by lenovo on 2017/4/21.
  */


object FPvalue {

  def probF(fr: Double, dn: Double, dd: Double): Double = {
    var f = fr
    var a = dn
    var b = dd
    var iv = 0
    var fp: Double = 0
    if (Math.floor(a / 2) * 2 == a) {
      fp = L401(a, f, b, iv) //even numerator df
      //return fp;
    } else if (Math.floor(b / 2) * 2 != b) {
      fp = L504(a, f, b, iv); //odd numerator df and odd denomiator df
      //return fp;
    }
    else { //odd numerator df and even denomiator df, do inverse of L401
      f = 1 / f;
      a = dd;
      b = dn;
      iv = 1;
      fp = L401(a, f, b, iv);

      //return fp;
    }
    fp = Math.max(fp, 0.0);
    fp
  }

  def L504(a: Double, f: Double, b: Double, iv: Double): Double = {
    val q = a * f / (a * f + b)
    val sa = Math.sqrt(q)
    val sl = Math.log(sa)
    val ca = Math.sqrt(1 - q)
    val cl = Math.log(ca)
    val al = Math.atan(sa / Math.sqrt(-sa * sa + 1))
    var fp = 1 - 2 * al / Math.PI
    var r: Double = 0
    var c: Double = 0
    var n: Int = 0
    if (b != 1) {
      c = Math.log(2 * sa / Math.PI)
      fp -= Math.exp(c + cl)
      if (b != 3) {
        n = Math.floor((b - 3) / 2).toInt
        for (i <- 1 to n) {
          val x: Double = (2 * i + 1);
          val y = (x - 1) / x
          r = r + Math.log(y);
          val rr = r + cl * x + c;
          if (rr > -78.4) {
            fp -= Math.exp(rr);
          }
        }

      }
    }

    if (a != 1) {
      c = r
      if (b > 1) c += Math.log(b - 1)
      c += Math.log(2 / Math.PI) + sl + cl * b
      if (c > -78.4) fp += Math.exp(c)
      if (a != 3) {
        n = Math.floor((a - 3) / 2).toInt
        r = 0
        if (a != 3) {
          n = Math.floor((a - 3) / 2).toInt;
          r = 0;
          for (i <- 1 to n) {
            val x: Double = (i * 2 + 1);
            r += Math.log((b + x - 2) / x);
            val rr = r + sl * (x - 1) + c;
            if (rr > -78.4) {
              fp += Math.exp(rr);
            }
          }
        }
      }
    }
    fp
  }


  def L401(a: Double, f: Double, b: Double, iv: Double): Double = {
    val q = a * f / (a * f + b)
    val ql = Math.log(q)
    var fp: Double = 0
    val c = Math.log(1 - q) * b / 2
    var n: Int = 0
    if (c > -78.4) fp = Math.exp(c)

    if (a != 2) {
      n = Math.floor(a / 2 - 1).toInt
      var r: Double = 0
      for (i <- 1 to n) {
        val x: Double = (2 * i);
        r += Math.log(b + x - 2) - Math.log(x) + ql;
        if (r + c > -78.4) {
          fp += Math.exp(r + c);
        }
      }
    }

    if (iv == 1) fp = 1 - fp
    fp
  }


  def main(args: Array[String]): Unit = {
    println(probF(1.1671568627451, 9, 9));
    println(Math.log(0.667));
  }

}
